package com.Angaliwa.Whiteboard{
	import com.Angaliwa.Core;
	import com.Angaliwa.DaisyChain;
	import com.Angaliwa.StageHandler;
	import com.Angaliwa.Whiteboard;
	
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.ui.Keyboard;
	import flash.utils.Timer;
	
	import mx.containers.Canvas;
	import mx.effects.Move;
	import mx.effects.easing.Elastic;
	import mx.events.EffectEvent;
	import mx.events.TweenEvent;
	
	public class Hand {
		public var enabled:Boolean=false,
				   whiteboard:Whiteboard;
		
		/*
			Available daisyChain actions:
			- startDrag
			- endDrag
			- dragging
			- restorePositionUpdate
			- restorePosition
		*/
		public var daisyChain:DaisyChain = new DaisyChain(this),
				   stageHandler:StageHandler = Core.g('stageHandler');
		
		private var isDragging:Boolean=false,
					needsRestore:Boolean=false,
					timer:Timer,
					mv:Move;
		
		public function init():void{
			// Set the default width/height, in case it is 
			// not specified by the user.
			whiteboard.settings.setDefaults({innerWidth:4000,innerHeight:4000,
											 restoreTimeout:0,restoreThreshold: 10,
											 restoreEasingEffect:Elastic.easeOut,
											 restoreDuration: 1500});
			
			// We need to disable the scrollbars to avoid weird 
			// effects when using the hand tool.
			whiteboard.container.verticalScrollPolicy = "off";
			whiteboard.container.horizontalScrollPolicy = "off";
			
			// Configure the inner-board
			var innerBoard:Canvas = new Canvas();
			innerBoard.horizontalScrollPolicy="off";
			innerBoard.verticalScrollPolicy="off";
			innerBoard.width = whiteboard.settings.get('innerWidth');
			innerBoard.height= whiteboard.settings.get('innerHeight');
			innerBoard.x = (whiteboard.board.width/2)-(innerBoard.width/2);
			innerBoard.y = (whiteboard.board.height/2)-(innerBoard.height/2);
			
			// Debug.
			whiteboard.board.setStyle("backgroundColor", 0xbbbbbb);
			innerBoard.setStyle("backgroundColor", 0xffffff);
			
			// Fetch all possibly created layers from board, and move them
			// to innerBoard.
			if(whiteboard.board.getChildren().length > 0)
				for(var i:int=0; i < whiteboard.board.getChildren().length; i++)
					innerBoard.addChild(whiteboard.board.getChildAt(i));
			
			// To avoid the drawing to 'stick' to the mouse when it leaves
			// the whiteboard, we'll finish the drawing when the mouse
			// leaves the whiteboard.
			innerBoard.addEventListener(MouseEvent.MOUSE_DOWN, startDrag);
			innerBoard.addEventListener(MouseEvent.MOUSE_UP, endDrag);
			innerBoard.addEventListener(MouseEvent.MOUSE_MOVE, dragging);
			innerBoard.addEventListener(MouseEvent.ROLL_OUT, endDrag);
			
			// If StageHandler is enabled, add keyboard functionality to
			// the mix. BETA.
			var old:String;
			stageHandler.key({keyCode:Keyboard.SPACE}, 
					function():void{
						old = whiteboard.enabledFeature;
						whiteboard.enableFeature('hand');
					}, 
					function():void{
						if(old)
							whiteboard.enableFeature(old);
						
						old="";
					});
			
			/*Core.g('stageHandler')
						.key({ctrlKey:true},
								function():void{trace('CTRL!')},
								function():void{trace('bubai CTRL!') })
						.key({keyCode:Keyboard.SPACE}, 
								function():void{ trace('spacebar!') },
								function():void{ trace('spacebar gone!') });
			*/
			
			// Add the innerBoard to the stage
			whiteboard.board.addChild(innerBoard);
			whiteboard.innerBoard = innerBoard;
		}
		
		public function startDrag(e:MouseEvent=undefined):void{
			if(enabled && !isDragging){
				if(mv){
					mv.stop();
					mv=null;
				}
				
				whiteboard.innerBoard.startDrag();
				isDragging=true;
				daisyChain.run('startDrag', e);
			}
		}
		
		private function dragging(e:MouseEvent):void{
			if(enabled && isDragging)
				daisyChain.run('dragging',e);
		}
		
		public function endDrag(e:MouseEvent=undefined):void{
			if(enabled && isDragging){
				whiteboard.innerBoard.stopDrag();
				
				isDragging=false;
				
				if(whiteboard.settings.get('restoreTimeout')>0){
					if(timer) timer.stop();
					
					timer = new Timer(whiteboard.settings.get('restoreTimeout'), 1);
					timer.addEventListener(TimerEvent.TIMER, restorePosition);
					timer.start();
				}
				else restorePosition();
				
				daisyChain.run('endDrag', e);
			}
		}
		
		public function stopRestorePosition():void{
			if(timer) timer.stop();
			if(mv) mv.stop();
			
			isDragging=false;
		}
		
		public function restorePosition(e:TimerEvent=undefined):void{
			stopRestorePosition();
			
			var maxX:int  = whiteboard.board.width, 
				maxY:int  = whiteboard.board.height,
				curX:int  = whiteboard.innerBoard.x,
				curY:int  = whiteboard.innerBoard.y,
				width:int = whiteboard.innerBoard.width,
				height:int= whiteboard.innerBoard.height,
				halfX:int = Math.floor((maxX/100)*whiteboard.settings.get('restoreThreshold')),
				halfY:int = Math.floor((maxY/100)*whiteboard.settings.get('restoreThreshold'));
			
			mv = new Move(whiteboard.innerBoard);
			
			if(whiteboard.settings.get('restoreEasingEffect'))
				mv.easingFunction = whiteboard.settings.get('restoreEasingEffect');
			
			mv.duration = whiteboard.settings.get('restoreDuration');
			mv.xFrom=curX;
			mv.yFrom=curY;
			mv.addEventListener(TweenEvent.TWEEN_UPDATE, function(e:TweenEvent):void{
				daisyChain.run('restorePositionUpdate');
			});
			mv.addEventListener(EffectEvent.EFFECT_END, function(e:EffectEvent):void{
				if(mv) mv.stop();
				mv=null;
			});
			
			if(curX>halfX)
				mv.xTo = 0;
			else if(curX < (0-width)+(maxX-halfX))
				mv.xTo = 0-(width-maxX);
			
			if(curY > halfY)
				mv.yTo = 0;
			else if(curY < (0-height)+maxY-halfY)
				mv.yTo= 0-(height-maxY);
			
			mv.play();
			
			daisyChain.run('restorePosition');
		}
	}
}